home *** CD-ROM | disk | FTP | other *** search
- ******************************************************************
- * COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
- * - Note: This is a real, live, actual, registered copyright,
- * and should be treated as such. This source code is from
- * the book "68000 Assembly Language", Krantz and Stanley,
- * Addison-Wesley Publishing Company, Reading, MA, 1986.
- *
- * Permission granted by the authors for non-commercial use
- * in programs released to the public domain, as long as this
- * copyright notice remains attached and visible.
- *
- *****************************************************************
- * PRINTF - subset/superset of C printf standard I/O function
- * Control args:
- *
- * push last parameter in control string first, then next-to
- * last, etc. Push address of control string last.
- *
- * %d: print signed decimal word
- * %u: print unsigned decimal word
- * %D: print signed decimal longword
- * %U: print unsigned decimal longword
- * %x: print hexadecimal word
- * %X: print hexadecimal longword
- * %s: print null terminated string
- * %c: print character
- * %v: cursor (x,y) - push Y, then X, as words.
- * %default: print next character as literal
- *****************************************************************
- xdef printf
- xref case,putc,cursor
- *****************************************************************
- * Local variable displacement definitions
- leftj equ -2 * left justify displacement
- field equ -4 * field width displacement
- signf equ -6 * sign flag
- *****************************************************************
- printf:
- link a6,#-6 * make 2 (word) local vars
- movem.l d0-d6/a0-a2,-(a7)
- move.l 8(a6),a1 * get control string address
- lea 12(a6),a2 * get pointer to parameters
- loop:
- move.b (a1)+,d0 * get control string character
- beq exit * quit if it's a null.
- ext.w d0 * clear high byte
- cmp.b #'%',d0 * see if it's control flag
- bne no_ctl * branch if not
- clr.w leftj(a6) * clear left justify flag
- clr.w field(a6) * clear field width
- clr.w signf(a6) * clear sign flag
- lp0pf:
- move.b (a1)+,d0 * get control string character
- ext.w d0 * clear high byte
- cmp.b #'-',d0 * is it minus?
- bne sk0pf * no, keep going
- move.w #1,leftj(a6) * set left justify flag
- bra lp0pf * try for next char
- sk0pf:
- cmp.b #'0',d0 * is it smaller than a digit?
- blt sk1pf * yes, continue processing
- cmp.b #'9',d0 * is it larger than a digit?
- bgt sk1pf * yes, continue processing
- move.w field(a6),d1 * get current field size
- mulu #10,d1 * shift left one decimal digit
- and.w #$000F,d0 * make ASCII digit binary
- add.w d0,d1 * add current digit
- move.w d1,field(a6) * store answer
- bra lp0pf * get next format char
- sk1pf:
- move.l #dispatch,a0 * get case table address for case
- bra case * go do case select.
- no_ctl:
- move.w d0,-(a7) * push character
- bsr putc * print it
- addq.l #2,a7 * trash parameter
- bra loop * do it again.
- exit:
- movem.l (a7)+,d0-d6/a0-a2
- unlk a6
- rts
- *****************************************************************
- d_arg:
- move.w (a2)+,d0 * get value, move pointer
- ext.l d0 * convert to common format
- bsr sign * print sign, if any, take abs()
- bra printdec * go print value
- *****************************************************************
- u_arg:
- move.w (a2)+,d0 * get value, move pointer
- and.l #$0000FFFF,d0 * zero out high word
- bra printdec * go print value
- *****************************************************************
- D_arg:
- move.l (a2)+,d0 * get value, move pointer
- bsr sign * print sign, if any, take abs()
- bra printdec * go print value
- *****************************************************************
- U_arg:
- move.l (a2)+,d0 * get value, move pointer
- bra printdec * print decimal value
- *****************************************************************
- * SIGN - print sign if needed and takes abs() of value
- sign:
- tst.l d0 * is it negative?
- bpl sk0_sg * exit if not
- move.w #-1,signf(a6) * flag sign needed
- subq.w #1,field(a6) * take away one for sign
- neg.l d0 * change the sign
- sk0_sg:
- rts
- *****************************************************************
- * printdec - common decimal output routine. Value in D0.
- printdec:
- clr.w d1 * output digit count
- lp0_pd:
- divu #10,d0 * divide number by 10
- bvs o_flow * number too large
- swap d0 * get remainder in d0.w
- move.w d0,-(a7) * push digit
- addq.w #1,d1 * bump digit count
- clr.w d0 * get rid of remainder
- swap d0 * put quotient into d0.w
- tst.w d0 * zero means we're done
- bne lp0_pd * jumps if not done.
- move.w d1,d6 * used for field adjust
- bsr prefix * do prefix spaces
- subq.w #1,d1 * adjust loop index counter
- lp2_pd:
- add.w #$30,(a7) * make digit TOS into ASCII
- bsr putc * output digit
- addq.l #2,a7 * eat digit from TOS
- dbra d1,lp2_pd * output all digits
- bsr postfix * do postfix spaces
- bra loop * exit to control parser
- o_flow:
- move.l #oflowstr,-(a7) * push control string address
- bsr printf * print it
- addq.l #4,a7 * adjust stack
- bra loop * continue
- oflowstr:
- dc.w '*overflow*',0
- *****************************************************************
- * PREFIX - outputs prefix spaces and/or sign
- prefix:
- tst.w field(a6) * check if field nonzero
- ble chksign * if zero, just boogie on out
- tst.w leftj(a6) * left justify selected?
- bne chksign * jump if no
- sub.w d6,field(a6) * digits allowed - digits actual
- ble chksign * exit if no spaces needed
- lp0_pr:
- move.w d0,-(a7) * save d0 across call to _put
- move.w #' ',-(a7) * space to output
- bsr putc * output the space
- addq.l #2,a7 * adjust stack
- move.w (a7)+,d0 * retrieve d0
- subq.w #1,field(a6) * decrement loop index
- bne lp0_pr * do again if more spaces needed
- chksign:
- tst.w signf(a6) * sign needed?
- beq chkexit * jump if no
- move.l d0,d2 * save d0 across call to _put
- move.w #' -',-(a7) * push sign
- bsr putc * output it
- addq.l #2,a7 * adjust stack
- move.l d2,d0 * retrieve argument
- chkexit:
- rts
- *****************************************************************
- * POSTFIX - prints postfix spaces in field
- postfix:
- sub.w d6,field(a6) * digits allowed - digits actual
- ble sk1_po * exit if no spaces needed
- lp0_po:
- move.w #' ',-(a7) * space to output
- bsr putc * output the space
- addq.l #2,a7 * adjust stack
- subq.w #1,field(a6) * decrement loop index
- bne lp0_po * do again if more spaces needed
- sk1_po:
- rts
- *****************************************************************
- x_arg:
- move.w #3,d1 * number of digits to print
- move.w #4,d6 * used for field adjust
- move.w (a2)+,d2 * transfer output value
- swap d2 * position output value
- bra printhex * go print it
- *****************************************************************
- X_arg:
- move.w #7,d1 * number of digits to print
- move.w #8,d6 * used for field adjust
- move.l (a2)+,d2 * transfer output value
- bra printhex * go print it
- *****************************************************************
- * PRINTHEX - outputs value held in D2 in hex. D1 is digit count
- printhex:
- bsr prefix * output prefix spaces
- lp0ph:
- move.l #hexdigits,a0 * address of translate table
- rol.l #4,d2 * put MSD in low four bits
- move.w d2,d0 * we're only interested in LSD
- and.w #$000F,d0 * so we hack off all but LSD
- move.b 0(a0,d0.w),d0 * get digit
- move.w d0,-(a7) * push for output
- bsr putc * output it
- addq.l #2,a7 * trash parameter
- dbra d1,lp0ph * loop for next digit
- bsr postfix * do postfix spaces
- bra loop * return to control string parser
- hexdigits:
- dc.w '0123456789ABCDEF'
- *****************************************************************
- s_arg:
- move.l (a2),a0 * get string address from stack
- clr.w d6 * get strlen for field adjust
- slen:
- tst.b (a0)+ * look for terminal null
- beq sk0_sa * jump if found
- addq.w #1,d6 * increment string length counter
- bra slen * look at next byte
- sk0_sa:
- move.l (a2)+,a0 * get string address again
- bsr prefix * print prefix spaces
- lp0_sa:
- tst.b (a0) * end of string?
- bne sk1_sa * no, keep going
- bsr postfix * print postfix spaces
- bra loop * continue parsing format string
- sk1_sa:
- move.b (a0)+,d0 * get char from string
- move.w d0,-(a7) * push for output
- bsr putc * output it
- addq.l #2,a7 * adjust stack
- bra lp0_sa * continue
- *****************************************************************
- c_arg:
- move.w (a2)+,-(a7) * get argument
- bsr putc * send it out
- addq.l #2,a7 * adjust stack
- bra loop * continue
- *****************************************************************
- v_arg:
- move.l (a2)+,-(a7) * move both args at once
- bsr cursor * perform function
- addq.l #4,a7 * adjust stack
- bra loop * continue parse of control str
- *****************************************************************
- * DEFAULT: user has specified unknown control argument
- default:
- move.w d0,-(a7) * we'll just print it.
- bsr putc * so there it goes!
- addq.l #2,a7 * adjust stack
- bra loop * that's all for here
- *****************************************************************
- * Case dispatch table for printf
- dispatch:
- dc.w 9 * number of valid options
- dc.b 0,'d' * %d print signed decimal word
- dc.l d_arg
- dc.b 0,'u' * %u print unsigned decimal word
- dc.l u_arg
- dc.b 0,'D' * %D print signed decimal longword
- dc.l D_arg
- dc.b 0,'U' * %U print unsigned decimal longword
- dc.l U_arg
- dc.b 0,'x' * %x print hex word
- dc.l x_arg
- dc.b 0,'X' * %X print hex longword
- dc.l X_arg
- dc.b 0,'s' * %s print null terminated string
- dc.l s_arg
- dc.b 0,'c' * %c print character
- dc.l c_arg
- dc.b 0,'v' * %v set cursor (X,Y)
- dc.l v_arg
- dc.l default * all unknown cases handled here
-
- end